"""
用于多个接口并发，或单一接口并发。使用gather实现结果收集
调用方法：
    aq = AsyncRequest(cookies,server)
    request_list= [{"url":"","data":"","content_type":""},{"url":"","data":""},{"url":"","data":""}……]
    asyncio.run(aq.do_get(request_list, 1))
"""
import asyncio
import requests
from bson import json_util
import re
from base.logcontrol import logger
from config import CONTENT_TYPE


class AsyncRequest:

    def __init__(self, host: str = "", cookies=None):
        self.host = host
        self.cookies = cookies

    def post(self, request_list: list = None, request: dict = None, count: int = 1):
        """
        请求多个接口；也可以单接口
        :param request_list: [{url:"",data:"",content_type:""},]
        :param request:{url:"",data:"",content_type:""}
        :param count: 请求次数
        :return:
        """

        cookie = self.cookies
        logger.debug(f"\nASYNC POST请求列表：\n"
                     f"\trequest_list:{request_list}\n"
                     f"\trequest:{request}\n"
                     f"\tcount:{count}\n")

        async def do_post() -> json_util:
            async def __post(__request):
                req_content_type = __request.get("content_type", "default")
                headers = {
                    "content_type": CONTENT_TYPE.get(req_content_type)
                }
                req_cookies = None
                if isinstance(cookie, str):
                    headers.update({"cookie": cookie.strip(" ")})
                else:
                    req_cookies = cookie
                __data = __request.get("data")

                url = self.host + __request.get("url")
                if isinstance(__data, str):
                    pattern = re.compile("^([A-Za-z]+=[A-Za-z0-9]*&?)*$")
                    if not re.match(pattern, __data):
                        r = {"success": False,
                             "info": "参数非法",
                             "data": __request.get("data")
                             }
                        logger.error(f"\n\tERROR! info:{r}\n")
                        return r

                req_data = None
                req_json = None
                if req_content_type.upper() == "FORM":
                    req_data = __data
                else:
                    req_json = __data

                logger.debug(f"\nDoPost: \n"
                             f"\tcontent_type:{req_content_type}\n"
                             f"\turl:{url}\n"
                             f"\tdata:{__data}\n"
                             f"\theader:{headers}\n")
                r = requests.request(method="POST",
                                     url=url,
                                     data=req_data,
                                     json=req_json,
                                     headers=headers,
                                     cookies=req_cookies)
                return r.json()

            tasks = []
            if request_list:
                tasks += [asyncio.create_task(__post(_)) for _ in request_list] * count
            if request:
                tasks += [asyncio.create_task(__post(request))] * count
            logger.debug(f"\n\t共{len(tasks)}个请求\n")
            result = await asyncio.gather(*tasks)
            resp = {"success": True, "data": result}
            logger.debug(f"\n\t执行结果：{resp}\n")
            return resp

        return asyncio.run(do_post())

    def get(self, request_list: list = None, request: dict = None, count: int = 1) -> json_util:
        """
        请求多个接口；也可以单接口
        :param request_list: [{url:"",data:"",content_type:""},]
        :param request:{url:"",data:"",content_type:""}
        :param count: 请求次数
        :return:
        """

        cookie = self.cookies
        logger.debug(f"\nASYNC GET请求列表：\n"
                     f"\trequest_list:{request_list}\n"
                     f"\trequest:{request}\n"
                     f"\tcount:{count}\n")

        async def do_get() -> json_util:

            async def __get(__request):
                headers = {
                    "content_type": CONTENT_TYPE.get(__request.get("content_type", "default"))
                }
                req_cookies = None
                if isinstance(cookie, str):
                    headers.update({"cookies": cookie.strip(" ")})
                else:
                    req_cookies = cookie
                req_content_type = __request.get("content_type", "default")
                url = self.host + __request.get("url")
                __data = __request.get("data")
                logger.debug(f"\nDoGet: \n"
                             f"\tcontent_type:{req_content_type}\n"
                             f"\turl:{url}\n"
                             f"\tdata:{__data}\n"
                             f"\theader:{headers}\n")
                r = requests.request(method="GET",
                                     url=url,
                                     param=__data,
                                     headers=headers,
                                     cookies=req_cookies)
                logger.debug(f"Response：{r.content}")
                return r.json()

            tasks = []
            if request_list:
                tasks += [asyncio.create_task(__get(_)) for _ in request_list] * count
            if request:
                tasks += [asyncio.create_task(__get(request))] * count
            result = await asyncio.gather(*tasks)
            resp = {"success": True, "data": result}
            logger.debug(f"\n\t执行结果：{resp}\n")
            return resp

        return asyncio.run(do_get())
